﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using FikriKibar.Business.Abstract;
using FikriKibar.Common.Entities;
using FikriKibar.Common.Enums;
using FikriKibar.Common.Exceptions;
using FikriKibar.Common.Helpers;
using FikriKibar.Common.Validation.FluentValidation.User;
using FikriKibar.DataAccess;
using FikriKibar.DataAccess.Abstract;
using FikriKibar.Entities.Composite.UserModels;
using FikriKibar.Entities.Concrete;
using FikriKibar.Globalization;

namespace FikriKibar.Business.Concrete
{
    public class SessionManager : ISessionService
    {
        #region Global Declarations
        private readonly ISessionDal _sessionDal = new EfSessionDal();

        private readonly ISessionHistoryDal _sessionHistoryDal = new EfSessionHistoryDal();

        private readonly IUserDal _userDal = new EfUserDal();
        private readonly ILanguageDal _languageDal = new EfLanguageDal();
        private readonly IRoleService _roleService = new RoleManager();

        private readonly IUserGroupRoleLineDal _userGroupRoleLineDal = new EfUserGroupRoleLineDal();

        #endregion
        #region Methods
        public LoginModel Login()
        {
            var loginModel = new LoginModel
            {
                LanguageList = _languageDal.Filter(e => e.IsApproved)
            };

            var identity = Thread.CurrentPrincipal.Identity;

            var fikriKibarIdentity = (FikriKibarIdentity)identity;
            if (!fikriKibarIdentity.RememberMe)
            {
                return loginModel;
            }
            loginModel.Username = fikriKibarIdentity.Username;
            loginModel.Password = fikriKibarIdentity.Password;
            loginModel.RememberMe = fikriKibarIdentity.RememberMe;
            return loginModel;
        }
        public void Login(LoginModel model)
        {
            var validator = new LoginValidator(model);

            model.User = new User
            {
                Username = model.Username,
                Password = model.Password
            };

            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }

            var user = _userDal.GetByUsername(model.Username);
            if (user == null)
            {
                throw new NotFoundException(Resources.NotFound);
            }
            if (!user.IsApproved)
            {
                throw new NotApprovedException(Resources.ThisRecordNotApproved);
            }

            if (user.Password != model.Password.ToSha512())
            {
                throw new NotFoundException(Resources.PasswordIncorrect);
            }

            var sessionsOfIdentity = _sessionDal.Filter(e => e.CreatedBy == user.Id);
            if (sessionsOfIdentity != null)
            {
                foreach (var sessionOfIdentity in sessionsOfIdentity)
                {
                    MoveToHistory(sessionOfIdentity, LogoutOptions.InvalidLogout);
                }
            }

            var session = new Session
            {
                CreatedBy = user.Id,
                CreateDate = DateTime.Now,
            };
            _sessionDal.Add(session);


            if (_roleService.GetRolesByUserId(user.Id).Count <= 0)
            {
                throw new NotApprovedException(Resources.ThisRecordNotApproved);
            }

            var userRoles = _roleService.GetRolesByUserId(user.Id).Select(role => role.Id).ToList();


            var fikriKibarIdentity = new FikriKibarIdentity
            {
                UserId = user.Id,
                Username = user.Username,
                Password = !model.RememberMe ? null : model.Password,
                FirstName = user.FirstName,
                LastName = user.LastName,
                IsAuthenticated = true,
                LanguageCode = user.Language.LanguageCode,
                RememberMe = model.RememberMe,
                Name = user.FullName,
                UserRoles = userRoles
            };

            var fikriKibarPrincipal = new FikriKibarPrincipal(fikriKibarIdentity);
            Thread.CurrentPrincipal = fikriKibarPrincipal;
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(fikriKibarIdentity.LanguageCode);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(fikriKibarIdentity.LanguageCode);


        }
        public void Logout(LogoutOptions logoutOptions)
        {
            var fikriKibarIdentity = (FikriKibarIdentity)Thread.CurrentPrincipal.Identity;
            var identity = fikriKibarIdentity;
            var sessionsOfIdentity = _sessionDal.Filter(e => e.CreatedBy == identity.UserId);
            if (sessionsOfIdentity == null) return;
            foreach (var session in sessionsOfIdentity)
            {
                MoveToHistory(session, logoutOptions);
            }
            var roles = new List<int> { 0 };
            fikriKibarIdentity = new FikriKibarIdentity
            {
                UserId = 0,
                IsAuthenticated = false,
                Name = "Guest",
                Username = "Guest",
                RememberMe = false,
                LanguageCode = Thread.CurrentThread.CurrentCulture.ToString(),
                UserRoles = roles,
                FirstName = "",
                LastName = ""

            };
            var fikriKibarPrinciple = new FikriKibarPrincipal(fikriKibarIdentity);
            Thread.CurrentPrincipal = fikriKibarPrinciple;
        }
        private void MoveToHistory(Session session, LogoutOptions logoutOptions)
        {
            var sessionHistory = new SessionHistory
            {
                CreatedBy = session.CreatedBy,
                CreateDate = session.CreateDate,
                UpdateDate = DateTime.Now,
                LogoutType = logoutOptions.ToString()
            };
            _sessionHistoryDal.Add(sessionHistory);
            _sessionDal.Delete(session);
        }
        #endregion

    }
}
